package middleware

import (
	"govue3/controllers"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/go-redis/redis/v8"
	"go.uber.org/zap"
	"golang.org/x/time/rate"
)

// RateLimiter 限流器接口
type RateLimiter interface {
	Middleware() gin.HandlerFunc
}

// userLimiter 存储每个用户的限流信息
type userLimiter struct {
	lastBlockedTime time.Time
	limiter         *rate.Limiter
}

// RedisLimiter Redis 分布式限流器
type RedisLimiter struct {
	client *redis.Client
	limit  rate.Limit
	burst  int
}

// NewRedisLimiter 创建一个新的 Redis 限流器
func NewRedisLimiter(client *redis.Client, limit rate.Limit, burst int) *RedisLimiter {
	return &RedisLimiter{
		client: client,
		limit:  limit,
		burst:  burst,
	}
}

// Middleware 返回一个 Gin 中间件函数，用于 Redis 分布式限流
func (rl *RedisLimiter) Middleware() gin.HandlerFunc {
	base := &controllers.BaseController{}

	return func(c *gin.Context) {
		key := c.ClientIP()
		ctx := c.Request.Context()

		// 检查是否处于冷却期
		isCooling, err := rl.client.Exists(ctx, key+":cooldown").Result()
		if err != nil {
			zap.L().Error("检查冷却状态失败", zap.Error(err))
			base.Error(c, "请求失败，请稍后重试!")
			c.Abort()
			return
		}
		if isCooling > 0 {
			base.Error(c, "请求频繁，请稍后重试!")
			c.Abort()
			return
		}

		// 递增计数器
		count, err := rl.client.Incr(ctx, key).Result()
		if err != nil {
			zap.L().Error("递增计数器失败", zap.Error(err))
			return
		}

		// 设置计数器的过期时间（例如 1 分钟）
		expireDuration := 60 * time.Second
		if err := rl.client.Expire(ctx, key, expireDuration).Err(); err != nil {
			zap.L().Error("设置计数器过期时间失败", zap.Error(err))
		}

		// 检查是否超过 burst
		if count > int64(rl.burst) {
			// 设置冷却键，有效期 1 分钟
			if err := rl.client.Set(ctx, key+":cooldown", "blocked", 1*time.Minute).Err(); err != nil {
				zap.L().Error("设置冷却键失败", zap.Error(err))
			}
			base.Error(c, "请求失败，请稍后重试!")
			c.Abort()
			return
		}

		c.Next()
	}
}

// NewRateLimiter 根据配置创建限流器
func NewRateLimiter(rateLimit rate.Limit, burst int, redisClient *redis.Client) RateLimiter {
	return NewRedisLimiter(redisClient, rateLimit, burst)
}
